<!--
 * @Author: 熊志伟 xiongzhiwei
 * @Date: 2024-11-12 09:14:40
 * @LastEditors: 熊志伟 xiongzhiwei
 * @LastEditTime: 2024-12-25 13:53:07
 * @FilePath: \sr_system_manager_ui\src\components\FilePreview\index.vue
 * @Description: 文件预览
-->
<script setup lang="ts">
import { fileToPdfReq } from '@/api/common'
import service from '@/utils/request'
import { getFileExtension, getFileName } from '@/utils/utils'
// import VueOfficeDocx from '@vue-office/docx'
// import '@vue-office/docx/lib/index.css'
import VueOfficeExcel from '@vue-office/excel'
import '@vue-office/excel/lib/index.css'
import VueOfficePdf from '@vue-office/pdf'

const props = defineProps<{
  src: string
}>()
const emits = defineEmits(['onRendered', 'onError'])

const type = computed(() => {
  return getFileExtension(props.src?.toLowerCase()) || ''
})

const name = computed(() => {
  return getFileName(props.src?.toLowerCase()) || ''
})

const textContent = ref('')
const htmlCotent = ref('')
const pdfUrl = ref('')

function onRendered() {
  emits('onRendered')
}

function onError() {
  emits('onError')
}

// txt转码处理中文乱码问题
const transformTxt = (data: any) => {
  return new Promise((resolve) => {
    let reader = new FileReader();
    reader.readAsText(data, 'UTF-8');
    reader.onload = (e: any) => {
      const txtString = e.target.result
      // utf-8 的 中文编码 正则表达式
      const patrn = /[\u4E00-\u9FA5]/gi;
      // 检测当前文本是否含有中文（如果没有，则当乱码处理）
      // 两个格式的英文编码一样，所以纯英文文件也当成乱码再处理一次
      if (!patrn.exec(txtString)) {
        let reader_gb2312 = new FileReader()
        // 再拿一次纯文本，这一次拿到的文本一定不会乱码
        reader_gb2312.readAsText(data, 'gb2312')
        reader_gb2312.onload = e2 => {
          resolve(e2.target.result)
        }
      } else {
        resolve(txtString)
      }
    }
  })
}

function txtPreview(url) {
  service.get(url, {
    responseType: "blob",
    transformResponse: [
      async function (data) {
        return await transformTxt(data);
      },
    ],
  }).then(res => {
    res.data.then((data: any) => {
      textContent.value = data;
    })
  })
}

// doc和docx会有wps兼容性问题，转成html处理
function htmlPreview(url) {
  fetch(url).then(res => res.text()).then(html => {
    htmlCotent.value = html
  }).catch(error => {
    ElMessage.error('获取HTML内容出错：', error)
  });

}

const { runAsync: fileToPdf } = useRequest(fileToPdfReq, {
  manual: true
})

watch(type, async (val) => {
  if (val === 'txt') {
    txtPreview(props.src)
  } else if (['doc', 'docx', 'xls'].includes(val)) {
    const res = await fileToPdf({ fileName: name.value, fileUrl: props.src })
    if (getFileExtension(res?.toLowerCase()) === 'html') {
      pdfUrl.value = '' //重置pdf.value防止rendererror
      htmlPreview(res)
    } else {
      pdfUrl.value = res
    }
  } else if (val === 'pdf') {
    pdfUrl.value = props.src
  } else {
    pdfUrl.value = ''
  }
}, {
  immediate: true
})


</script>

<template>
  <div class="preview-wrapper" >
    <!-- <VueOfficeDocx class="w-full h-full" v-if="['docx'].includes(type!)" :src="props.src" @rendered="onRendered"
      @error="onError" /> -->
    <VueOfficeExcel class="w-full min-h-300px" v-if="['xlsx'].includes(type!)" :src="props.src" @rendered="onRendered"
      @error="onError" />
    <template v-else-if="['xls', 'pdf'].includes(type!)">
      <VueOfficePdf class="w-full h-full" v-if="pdfUrl" :src="pdfUrl" @rendered="onRendered" @error="onError" />
    </template>
    <template v-else-if="['doc', 'docx'].includes(type!)">
      <div class="w-full h-full bg-[#FFF] overflow-auto" v-html="htmlCotent"></div>
    </template>
    <div v-else-if="['jpg', 'png', 'jpeg'].includes(type)" class="w-full h-full flex flex-col justify-center items-center overflow-auto">
      <el-image :src="props.src" fit="cover"></el-image>
    </div>
    <div v-else-if="['txt'].includes(type)" class="w-full h-full bg-[#FFF]">{{ textContent }}</div>
    <div v-else class="empty">文件格式暂不支持预览</div>
  </div>
</template>

<style lang="scss" scoped>
.preview-wrapper {
  @apply w-full h-full;

  .empty {
    @apply bg-[#FFF] w-full h-full flex items-center justify-center min-h-300px;
  }
}
</style>